package generators;
import MortgageCore.Person;
import geography.Geography;
import data.LocalData;
import java.io.*;
import java.util.*;

/**
 *
 * @author Isaac Noble
 */
public class HouseholdGenerator {

    ArrayList<HouseholdInfo> all_info;
    protected Map<String, IncomeInfo> incomeDataByState = new HashMap<String, IncomeInfo>();
    int cur_index;

    private class IncomeInfo {
        List<Double> incomeValues;
        double median;
        double average;

        public IncomeInfo() {
            incomeValues = new ArrayList<Double>();
            median = 0;
            average = 0;
        }
    }

    public double getMedianIncome(String state) {
        return incomeDataByState.get(state).median;
    }

    public double getAverageIncome(String state) {
        return incomeDataByState.get(state).average;
    }

    public HouseholdGenerator(int num_households) throws IOException {
        Geography.Build();
        InputStream in_stream = LocalData.GetInputStream(LocalData.Input.HOUSEHOLD_FILE);
        InputStreamReader is_reader = new InputStreamReader(in_stream);
        BufferedReader reader = new BufferedReader(is_reader);

        all_info = new ArrayList<HouseholdInfo>();
        String line;
        while ((line = reader.readLine()) != null && num_households > 0) {

            HouseholdInfo info = new HouseholdInfo(line);
            all_info.add(info);
            num_households--;
        }
        reader.close();
        is_reader.close();
        in_stream.close();

        ComputeMedianIncomesByState();
    }

    private void ComputeMedianIncomesByState() {
        // for each household
        for(HouseholdInfo hi : all_info) {
            // get the state
            String state = hi.city.GetState().getStateCode();
            // if not in the hash map,
            if (!incomeDataByState.containsKey(state)) {
                // add state to hash map
                // add list to go with state
                IncomeInfo ii = new IncomeInfo();
                incomeDataByState.put(state, ii);
            }
            // get the income for the household and add it to the list
            IncomeInfo stateInfo = incomeDataByState.get(state);
            stateInfo.incomeValues.add(hi.salary);
        }

        // for each state in the hash map
        Set keys = incomeDataByState.keySet();
        Iterator iter = keys.iterator();
        while (iter.hasNext()) {
            IncomeInfo ii = incomeDataByState.get(iter.next());
            Collections.sort(ii.incomeValues);
            // compute the median income
            int numEntries = ii.incomeValues.size();
            if (numEntries > 0) {
                int midVal;
                if ((numEntries % 2) == 1) {    // odd
                    midVal = numEntries / 2;
                    ii.median = ii.incomeValues.get(midVal);
                } else {
                    midVal = numEntries / 2 - 1;
                    ii.median = ii.incomeValues.get(midVal);
                    ii.median += ii.incomeValues.get(midVal + 1);
                    ii.median /= 2;
                }
            } else {
                ii.median = 0;
            }
            // compute the average
            double average = 0;
            for (int j=0; j<numEntries; j++)
                average += ii.incomeValues.get(j);
            average /= (double) numEntries;
            ii.average = average;
        }
    }

    public HouseholdInfo GetNext()
    {
        if(cur_index >= all_info.size())
        {
            cur_index = 0;
        }
        HouseholdInfo info = all_info.get(cur_index);
        cur_index++;

        return info;
    }

    public static class HouseholdInfo
    {
        HouseholdInfo(String line)
        {
            salary = Double.parseDouble(GetValue(line, "INCOME"))/12.0;
            expenses = salary * 0.6 * Math.random();
            savings_rate = 0.4 * Math.random();
            city = Geography.GetCity(GetValue(line,"GEOID"));
            num_members = Integer.parseInt(GetValue(line, "SIZE"));
            race = GetValue(line,"RACE");
            type = GetValue(line,"TYPE");
            GetPeople(line, num_members);
        }

        private String GetValue(String line, String id)
        {
            int start = line.indexOf(id);
            start = line.indexOf(':', start);
            int end = line.indexOf(',', start);
            return line.substring(start+1, end);
        }

        private void GetPeople(String line, int size)
        {
            people = new ArrayList<Person>();
            int start;
            String sub_line = line;
            for(int i = 0; i < size; i++)
            {
                start = sub_line.indexOf("PERSON");
                sub_line = sub_line.substring(start+1);
                Person a_person = new Person();
                a_person.race = GetValue(sub_line,"RACE");
                a_person.age = Integer.parseInt(GetValue(sub_line,"AGE"));
                a_person.male = true;
                if(GetValue(sub_line,"GENDER").equalsIgnoreCase("FEMALE"))
                {
                    a_person.male = false;
                }
                people.add(a_person);
            }
        }

        public ArrayList<Person> people;
        public double salary = 0;
        public double cost_of_living = 1.0;
        public double expenses = 0;
        public double savings_rate = 0;
        public String race;
        public String type;
        public int num_members = 0;
        public Geography.City city;
    }



}
